﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using StockTrader.Platform.Logging;
using StockTrader.Platform.Utilities.System;
using StockTrader.Stocks.General;
using StockTrader.Stocks.Utilities.Broker;
using StockTrader.Stocks.Utilities.Market;

namespace StockTrader.API.TradingAlgos
{
    public class Algo4_MultipleLotBuySellAnalyzer: ITradingAlgo
    {
        List<StockOrder> mOrders = new List<StockOrder>();
        List<Tick> ticks = new List<Tick>();

        readonly double mPercChangeThresholdForMarketDirection;
        readonly double mPercChangeThresholdForSquareOff;

        //if the price moves in the opposite direction (leading to a loss)
        //then mark losses if this is the percentage change.
        readonly double mStopLossPercentage;

        //if the profit percentage is above this price, 
        //then book profit.
        //else, hold on
        readonly double mMinimumProfitPercentage;

        double mAverageTradePrice = 0;
        int mTotalTickCount = 0;
        int mTickLastSquareOffDone = 0;
        readonly bool mUseProbableTradeValue;

        readonly bool mAllowShort;
        readonly bool mAllowLong;
        readonly double mPositionSpacingPerc;

        readonly List<string> mOrderReferenceNumbers = new List<string>();
        readonly bool mMock;
        readonly bool mIsReplayMode;
        bool bReplayDone = false;
        readonly IBroker mBroker;
        readonly string mStockCode;
        readonly int mQuantity;
        readonly InstrumentType mInstrumentType;
        readonly DateTime mExpiryDate;

        //readonly double mPercentageChangeForFreshBuy;
        //readonly double mPercentageChangeForShortSquareOff;
        //readonly double mPercentageChangeForFreshShort;
        //readonly double mPercentageChangeForLongSquareOff;
        readonly double mLongCeilingPrice;
        readonly double mShortFloorPrice;

        readonly int mMaxTotalPositions, mMaxLongPositions, mMaxShortPositions;
        readonly double mBrokerage; // in percentage

        readonly string mTraceFileName;
        readonly string mTickFileName;
        readonly string mReplayTickFile;


        double ltp = 0;
        double mCummulativeProfitBooked = 0;
        double mNettFruitIfSquaredOffAtLTP = 0;

        string mPositionsFile;

        double mTotalProfit;
        public double TotalProfit
        {
            get { return mTotalProfit; }
        }
       
        double mTotalBrokerage = 0;
        public double TotalBrokerage
        {
            get { return mTotalBrokerage; }
        }

        double mTotalTurnover;
        public double TotalTurnover
        {
            get { return mTotalTurnover; }
            private set { mTotalTurnover = value; }
        }

        private int mTotalBuyTrades;
        public int TotalBuyTrades
        {
            private set { mTotalBuyTrades = value; }
            get
            {
                return mTotalBuyTrades;
            }
        }
        private int mTotalSellTrades;
        public int TotalSellTrades
        {
            private set { mTotalSellTrades = value; }
            get
            {
                return mTotalSellTrades;
            }
        }
        private int mTotalFailedOrders;
        public int TotalFailedOrders
        {
            private set { mTotalFailedOrders = value; }
            get
            {
                return mTotalFailedOrders;
            }
        }


        // ------- Core Algo methods start -------- //

        public Algo4_MultipleLotBuySellAnalyzer(bool mock,
            bool bIsReplayMode,
            string replayTickFile,
            string positionsFile,
            bool useProbableTradeValue,
            double percChangeForMarketDirectionChange,
            double percChangeThresholdForSquareOff,
            double stopLossPercentage,
            double minimumProfitPercentage,
            bool allowShort,
            bool allowLong,
            List<StockOrder> startOrders,
            IBroker broker,
            string stockCode,
            int quantity,
            InstrumentType instrumentType,
            DateTime expiryDate,
            int maxTotalPositions,
            int maxLongPositions,
            int maxShortPositions,
            double longCeilingPrice,
            double shortFloorPrice,
            double positionSpacingPerc,
            double brokerage)
        {
            mStockCode = stockCode;
            
            string guidId = Guid.NewGuid().ToString();
            mTickFileName = "C:\\StockTickFiles\\" + mStockCode + "-" + DateTime.Today.ToString("yyyyMMdd") + "-" + guidId + ".txt";
            mTraceFileName = "C:\\StockTraderLogs\\BSARunLog-" + mStockCode + "-" + DateTime.Today.ToString("yyyyMMdd") + "-" + guidId + ".txt";

            FileTracing.InitializeTraceSources(mTraceFileName);
            mIsReplayMode = bIsReplayMode;
            mReplayTickFile = replayTickFile;
            mMock = mock;

            mUseProbableTradeValue = useProbableTradeValue;
            mPercChangeThresholdForMarketDirection = percChangeForMarketDirectionChange;
            mPercChangeThresholdForSquareOff = percChangeThresholdForSquareOff;
            mStopLossPercentage = stopLossPercentage;
            mMinimumProfitPercentage = minimumProfitPercentage;
            mPositionsFile = positionsFile;
            mAllowShort = allowShort;
            mAllowLong = allowLong;

            if (startOrders != null)
            {
                foreach (StockOrder order in startOrders)
                {
                    if (order.OrderPosition != Position.None)
                    {
                        mOrders.Add(new StockOrder(order));
                    }
                }
            }
            mBroker = broker;

            mQuantity = quantity;
            mInstrumentType = instrumentType;
            mExpiryDate = expiryDate;
            mMaxTotalPositions = maxTotalPositions;
            mMaxLongPositions = maxLongPositions;
            mMaxShortPositions = maxShortPositions;
            mBrokerage = brokerage;
            mLongCeilingPrice = longCeilingPrice;
            mShortFloorPrice = shortFloorPrice;
            mPositionSpacingPerc = positionSpacingPerc;

            FileTracing.TraceInformation("START : " + DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString());
        }

        double GetTradeValueForAnalysis(DerivativeQuoteInformation di)
        {
            if (mUseProbableTradeValue)
            {
                if (di.ProbableNextTradeValue != -1)
                    return di.ProbableNextTradeValue;
            }
            if (di.LastTradedPriceDouble > 0)
            {
                return di.LastTradedPriceDouble;
            }
            return di.LastTradedPriceDouble;
        }

        public void MarketClosing()
        {
            Analyze(true);
        }

        public void AddTick(DerivativeQuoteInformation di, bool bMarketTick, bool? marketClosing)
        {
            if (marketClosing == null)
            {
                marketClosing = MarketUtils.IsTimeAfter315();
            }

            // Write to tickfile
            if (!mIsReplayMode && bMarketTick)
            {
                using (FileStream fs = new FileStream(mTickFileName, FileMode.Append, FileAccess.Write))
                {
                    using (StreamWriter sw = new StreamWriter(fs))
                    {
                        DateTime Now = DateTime.Now;
                        string str = di.UpdateTime.ToString("yyyyMMdd:HH:mm:ss") + ";" + di.LastTradedPriceDouble + ";" + di.BidPriceDouble +
                            ";" + di.OfferPriceDouble + ";" + di.BidQuantityInt + ";" + di.OfferQuantityInt + ";" + di.VolumeTradedInt;
                        sw.WriteLine(str);
                    }
                }
            }


            double tradeValue = GetTradeValueForAnalysis(di);

            // Stats
            mAverageTradePrice = (mAverageTradePrice + tradeValue) / mTotalTickCount;

            FileTracing.TraceVerbose("New Tick. LTP = " + tradeValue + ". OFFER=" + di.OfferPriceDouble + ". BID=" + di.BidPriceDouble);

            // di is the new tick here
            Tick tick = new Tick()
            {
                DerivativeInformation = di,
                HasFreshPositionBeenInitiatedInCurrentLeg = false,
                MarketDirection = MarketDirection.NONE,
                PercentageChangeFromLastPeak = 0,
                Order = null
            };

            // First tick
            if (ticks.Count == 0)
            {
                FileTracing.TraceVerbose("First tick. No analysis");
                ticks.Add(tick);
                return;
            }


            // --- Actual Analysis starts

            int lastIndex = ticks.Count - 1;
            Tick prevTick = ticks[lastIndex];
            DerivativeQuoteInformation prevDi = prevTick.DerivativeInformation;

            double newPercChangeFromLastTrendingTick = 100 * ((GetTradeValueForAnalysis(di) - GetTradeValueForAnalysis(prevDi)) / GetTradeValueForAnalysis(prevDi));

            tick.PercentageChangeFromLastPeak = newPercChangeFromLastTrendingTick;
            tick.MarketDirection = (newPercChangeFromLastTrendingTick > 0 ? MarketDirection.UP : MarketDirection.DOWN);

            // Second tick = di
            if (ticks.Count == 1)
            {
                FileTracing.TraceVerbose("Second tick. PercMarketChange=" + tick.PercentageChangeFromLastPeak);

                // Set the first peak as low or high
                ticks[0].MarketDirection = tick.MarketDirection == MarketDirection.UP ? MarketDirection.DOWN: MarketDirection.UP;

                ticks.Add(tick);

                Analyze(tick, marketClosing.Value);
                return;
            }

            // Main Analysis with >= 2 ticks

            System.Diagnostics.Debug.Assert(ticks.Count >= 2);

            // Same trend
            if (((prevTick.MarketDirection == MarketDirection.UP) && (newPercChangeFromLastTrendingTick >= 0)) ||
                ((prevTick.MarketDirection == MarketDirection.DOWN) && (newPercChangeFromLastTrendingTick <= 0)))
            {
                // Just replace last tick
                ticks[1] = tick;
            }
            else if (Math.Abs(newPercChangeFromLastTrendingTick) >= mPercChangeThresholdForMarketDirection)
            {
                // Trend changed by threshold, New peak detected
                ticks[0] = ticks[1];
                ticks[1] = tick;
                Analyze(tick, marketClosing.Value);
            }
        }

        bool Analyze(Tick tick, bool marketClosing)
        {
            if (ticks.Count < 2)
            {
                FileTracing.TraceVerbose("Cannot analyze, since less than 2 ticks");
                return false;
            }

            DerivativeQuoteInformation di = tick.DerivativeInformation;

            bool isBuy = tick.MarketDirection == MarketDirection.UP;

            int numOpenPositions = Math.Abs(mTotalBuyTrades - mTotalSellTrades);

            //bool isMoreBuyOpenPositions = mTotalBuyTrades > mTotalSellTrades;

            bool isLimitAvailable = numOpenPositions < mMaxTotalPositions;

            //bool isExtraTrade = isBuy && isMoreBuyOpenPositions;

            int endIndex = ticks.Count - 1;
            double percChange = ticks[endIndex].PercentageChangeFromLastPeak;

            //sort the orders first, so that orders with lower profits get squared off first.
            mOrders.Sort(new OrderSorter());

            bool orderPlaced = false;

            /////////////////////////////
            // SquareOff loop ///////////
            ////////////////////////////
            foreach (StockOrder singleOrder in mOrders)
            {
                if (orderPlaced)
                {
                    //only place one order during a tick, since the execution 
                    //of the order will fulfil one buyer or one seller, and
                    //we should now get the latest prices.
                    FileTracing.TraceVerbose("SquareOff: One order already placed in this tick, not attempting to SquareOff others");
                    break;
                }

                System.Diagnostics.Debug.Assert(singleOrder.OrderPosition != Position.None);

                if (marketClosing)
                {
                    FileTracing.TraceVerbose("Market closing: Attempting to SquareOff all open positions. OrderDetails=" + singleOrder);
                    orderPlaced = PossibleSquareOff(ticks[endIndex].DerivativeInformation, singleOrder);
                    continue;
                }

                // Direction PercChange below threshold , so no attemots to SquareOff , break out 
                if (Math.Abs(percChange) < mPercChangeThresholdForSquareOff)
                {
                    //this change is not sufficient to indicate a change in market direction
                    FileTracing.TraceVerbose("SquareOff: PercChange below \"PercChangeThresholdForSquareOff\" threshold, so no SquareOff attempts");
                    break;
                }

                //
                // SquareOff: market direction has changed, and percentage change is significant.
                // 
                if (percChange > 0)
                {
                    //market is going up
                    if (singleOrder.OrderPosition == Position.Sell)
                    {
                        //already short sold.
                        //either square off for profit, or for loss if the 
                        //percentage change is greater than the stop loss percentage
                        //FileTracing.TraceVerbose("attempting to square off order. OrderDetails=" + singleOrder);
                        orderPlaced = PossibleSquareOff(ticks[endIndex].DerivativeInformation, singleOrder);
                        FileTracing.TraceVerbose("SquareOff attempted: OrderPlaced=" + orderPlaced + ". OrderDetails=" + singleOrder);
                    }
                }
                else if (percChange < 0)
                {
                    //market is going down.
                    if (singleOrder.OrderPosition == Position.Buy)
                    {
                        //already bought.                           
                        //either square off for profit, or for loss if the 
                        //percentage change is greater than the stop loss percentage
                        //FileTracing.TraceVerbose("attempting to square off order. OrderDetails=" + singleOrder);
                        orderPlaced = PossibleSquareOff(ticks[endIndex].DerivativeInformation, singleOrder);
                        FileTracing.TraceVerbose("SquareOff attempted: OrderPlaced=" + orderPlaced + ". OrderDetails=" + singleOrder);
                    }
                }
            }


            // Internal State Check ////
            int numCurrentShortPositions = 0, numCurrentLongPositions = 0;
            for (int i = mOrders.Count - 1; i >= 0; i--)
            {
                if (mOrders[i].OrderPosition == Position.None)
                {
                    mOrders.RemoveAt(i);
                }
                else if (mOrders[i].OrderPosition == Position.Buy)
                {
                    numCurrentLongPositions++;
                }
                else if (mOrders[i].OrderPosition == Position.Sell)
                {
                    numCurrentShortPositions++;
                }
            }


            // Check 1
            // One SquareOff order already placed, not trying to place fresh order in this same tick, wait for next tick
            // return
            if (orderPlaced)
            {
                //only place one order during a tick, since the execution 
                //of the order will fulfil one buyer or one seller, and
                //we should now get the latest prices.
                FileTracing.TraceVerbose("FreshPositionChecks: One order already placed, not attempting to start new position");
                mTickLastSquareOffDone = mTotalTickCount;
                return true;
            }

            // Check 1.1
            // Wait for 10 ticks atleast from last squareoff to take an informed (not hasty) decision
            // true opportunity missed is OK rather than getting stuck in false one due to quick changes in price.
            if ((mTotalTickCount - mTickLastSquareOffDone) < 10)
            {
                FileTracing.TraceVerbose("FreshPositionChecks: Last SquareOff done recently, waiting to judge market direction to start new position");
                return false;
            }
            // Check 2
            if (mOrders.Count >= mMaxTotalPositions)
            {
                FileTracing.TraceVerbose("FreshPositionChecks: Discarding: MaxTotalPositions");
                return false;
            }

            // Check 3
            // Direction PercChange below threshold , so return 
            if (Math.Abs(percChange) < mPercChangeThresholdForMarketDirection)
            {
                //this change is not sufficient to indicate a change in market direction
                FileTracing.TraceVerbose("FreshPositionChecks: Discarding: PercChange below \"PercentageChangeForMarketDirection\" threshold, so no new position attempts");
                return false;
            }

            bool allowShortNewPos = true;
            bool allowLongNewPos = true;

            // Check 4
            // Minimize risk by allowing to balance out
            //already have a position in this leg, hence will place new order only to balance out buy/sell sides
            if (ticks[endIndex].HasFreshPositionBeenInitiatedInCurrentLeg)
            {

                // Balance out the short and long positions, so as to maintain effective stop loss
                // in case of a big "black swan" 
                int numOpenShortPositions = 0, numOpenLongPositions = 0;
                for (int i = mOrders.Count - 1; i >= 0; i--)
                {
                    if (mOrders[i].OrderPosition == Position.Buy)
                    {
                        numOpenLongPositions++;
                    }
                    else if (mOrders[i].OrderPosition == Position.Sell)
                    {
                        numOpenShortPositions++;
                    }
                }
                // if both are equal, then no need to create another positon in same leg (old behaviour)
                // only if imbalance then try to create the position
                if (numOpenLongPositions == numOpenShortPositions)
                {
                    FileTracing.TraceVerbose("FreshPositionChecks: Already Balanced out!");
                    return false;
                }
                else if (numOpenLongPositions > numOpenShortPositions)
                {
                    allowLongNewPos = false;
                }
                else
                {
                    allowShortNewPos = false;
                }
                FileTracing.TraceVerbose("FreshPositionChecks: Already have a position in this leg, still to balance out allow taking new position in same Leg");

                // TOREMOVECOMMENT
                // return false;
            }

            //market direction has changed, and percentage change is significant.

            /////////////////////////////////////////////////////////
            ///// Try taking 1 long or short position here /////////
            ////////////////////////////////////////////////////////
            // New Long position
            if (percChange > 0)
            {
                //market is going up
                if (mAllowLong)
                {
                    if (!allowLongNewPos || numCurrentLongPositions >= mMaxLongPositions)
                    {
                        FileTracing.TraceVerbose("FreshLong: Discarding: Hit MaxLongPositions!");
                    }
                    else
                    {
                        //buy a new lot
                        FileTracing.TraceVerbose("FreshLong: Attempting ...");

                        double lowPositionExistRange = 0, highPositionExistRange = 0;
                        bool orderValid = true;
                        double orderPrice = ticks[endIndex].DerivativeInformation.OfferPriceDouble;

                        // Apply LongCeiling price filter
                        if (mLongCeilingPrice > 0 && orderPrice > mLongCeilingPrice)
                        {
                            FileTracing.TraceVerbose("FreshLong: Discarding : LongCeilingPrice hit");
                            orderValid = false;
                        }

                        // Filter out the existing open position price ranges
                        for (int i = mOrders.Count - 1; i >= 0 && orderValid; i--)
                        {
                            if (mOrders[i].OrderPosition == Position.Buy)
                            {
                                // Place new leg orders 1% away from existing positions
                                // calculate the restrcited range and if the potential orderprice falls
                                // in this range then dont initiate this position as we already got a similar position
                                lowPositionExistRange = (1 - mPositionSpacingPerc / 100) * mOrders[i].OrderPrice;
                                highPositionExistRange = (1 + mPositionSpacingPerc / 100) * mOrders[i].OrderPrice;
                                if (orderPrice > lowPositionExistRange &&
                                    orderPrice < highPositionExistRange)
                                {
                                    FileTracing.TraceVerbose("FreshLong: Discarding: \"SpacingPerc\"");
                                    orderValid = false;
                                    break;
                                }
                            }
                        }
                        // Place only if order is out of exisitng position ranges
                        if (orderValid)
                        {
                            FileTracing.TraceVerbose("FreshLong: All checks passed, order is valid");
                            StockOrder newOrder = new StockOrder(Position.None, 0);
                            if (PlaceOrder(Position.Buy, newOrder, ticks[endIndex].DerivativeInformation))
                            {
                                //mTotalBuyTrades++;
                                System.Diagnostics.Debug.Assert(newOrder.OrderPosition != Position.None);
                                mOrders.Add(newOrder);
                                ticks[endIndex].HasFreshPositionBeenInitiatedInCurrentLeg = true;
                                ticks[endIndex].Order = newOrder;
                                FileTracing.TraceVerbose("FreshLong: Successful");
                                return true;
                            }
                            else
                            {
                                FileTracing.TraceVerbose("FreshLong: Failed due to IOC");
                            }
                        }
                    }
                }
            }
            // New Short position
            else if (percChange < 0)
            {
                //market is going down.
                if (mAllowShort)
                {
                    if (!allowShortNewPos || numCurrentShortPositions >= mMaxShortPositions)
                    {
                        FileTracing.TraceVerbose("FreshShort: Discarding: Hit MaxShortPositions!");
                    }
                    else
                    {
                        //sell a new lot          
                        FileTracing.TraceVerbose("FreshShort: Attempting ...");

                        double lowPositionExistRange = 0, highPositionExistRange = 0;
                        bool orderValid = true;
                        double orderPrice = ticks[endIndex].DerivativeInformation.OfferPriceDouble;

                        // Apply ShortFloor price filter
                        if (mShortFloorPrice > 0 && orderPrice < mShortFloorPrice)
                        {
                            FileTracing.TraceVerbose("FreshShort: Discarding : ShortFloorPrice has hit");
                            orderValid = false;
                        }

                        // Filter out the existing open position price ranges
                        for (int i = mOrders.Count - 1; i >= 0 && orderValid; i--)
                        {
                            if (mOrders[i].OrderPosition == Position.Sell)
                            {
                                // Place new leg orders 1% away from existing positions
                                // calculate the restrcited range and if the potential orderprice falls
                                // in this range then dont initiate this position as we already got a similar position
                                lowPositionExistRange = (1 - mPositionSpacingPerc / 100) * mOrders[i].OrderPrice;
                                highPositionExistRange = (1 + mPositionSpacingPerc / 100) * mOrders[i].OrderPrice;
                                if (orderPrice > lowPositionExistRange &&
                                    orderPrice < highPositionExistRange)
                                {
                                    FileTracing.TraceVerbose("FreshShort: Discarding : \"SpacingPerc\"");
                                    orderValid = false;
                                    break;
                                }
                            }
                        }
                        // Place only if order is out of exisitng position ranges
                        if (orderValid)
                        {
                            FileTracing.TraceVerbose("FreshShort: All checks passed, order is valid");
                            StockOrder newOrder = new StockOrder(Position.None, 0);
                            if (PlaceOrder(Position.Sell, newOrder, ticks[endIndex].DerivativeInformation))
                            {
                                //mTotalSellTrades++;
                                System.Diagnostics.Debug.Assert(newOrder.OrderPosition != Position.None);
                                mOrders.Add(newOrder);
                                ticks[endIndex].HasFreshPositionBeenInitiatedInCurrentLeg = true;
                                ticks[endIndex].Order = newOrder;
                                FileTracing.TraceVerbose("FreshShort: Successful");
                                return true;
                            }
                            else
                            {
                                FileTracing.TraceVerbose("FreshShort: Failed due to IOC ");
                            }
                        }
                    }
                }
            }

            return false;
        }

        /// <returns>true if an order was executed, else false</returns>
        bool Analyze1(bool marketClosing)
        {
            if (ticks.Count < 2)
            {
                FileTracing.TraceVerbose("Cannot analyze, since less than 2 ticks");
                return false;
            }
            int endIndex = ticks.Count - 1;
            double percChange = ticks[endIndex].PercentageChangeFromLastPeak;

            //sort the orders first, so that orders with lower profits get squared off first.
            mOrders.Sort(new OrderSorter());

            bool orderPlaced = false;

            /////////////////////////////
            // SquareOff loop ///////////
            ////////////////////////////
            foreach (StockOrder singleOrder in mOrders)
            {
                if (orderPlaced)
                {
                    //only place one order during a tick, since the execution 
                    //of the order will fulfil one buyer or one seller, and
                    //we should now get the latest prices.
                    FileTracing.TraceVerbose("SquareOff: One order already placed in this tick, not attempting to SquareOff others");
                    break;
                }

                System.Diagnostics.Debug.Assert(singleOrder.OrderPosition != Position.None);

                if (marketClosing)
                {
                    FileTracing.TraceVerbose("Market closing: Attempting to SquareOff all open positions. OrderDetails=" + singleOrder);
                    orderPlaced = PossibleSquareOff(ticks[endIndex].DerivativeInformation, singleOrder);
                    continue;
                }

                // Direction PercChange below threshold , so no attemots to SquareOff , break out 
                if (Math.Abs(percChange) < mPercChangeThresholdForSquareOff)
                {
                    //this change is not sufficient to indicate a change in market direction
                    FileTracing.TraceVerbose("SquareOff: PercChange below \"PercChangeThresholdForSquareOff\" threshold, so no SquareOff attempts");
                    break;
                }

                //
                // SquareOff: market direction has changed, and percentage change is significant.
                // 
                if (percChange > 0)
                {
                    //market is going up
                    if (singleOrder.OrderPosition == Position.Sell)
                    {
                        //already short sold.
                        //either square off for profit, or for loss if the 
                        //percentage change is greater than the stop loss percentage
                        //FileTracing.TraceVerbose("attempting to square off order. OrderDetails=" + singleOrder);
                        orderPlaced = PossibleSquareOff(ticks[endIndex].DerivativeInformation, singleOrder);
                        FileTracing.TraceVerbose("SquareOff attempted: OrderPlaced=" + orderPlaced + ". OrderDetails=" + singleOrder);
                    }
                }
                else if (percChange < 0)
                {
                    //market is going down.
                    if (singleOrder.OrderPosition == Position.Buy)
                    {
                        //already bought.                           
                        //either square off for profit, or for loss if the 
                        //percentage change is greater than the stop loss percentage
                        //FileTracing.TraceVerbose("attempting to square off order. OrderDetails=" + singleOrder);
                        orderPlaced = PossibleSquareOff(ticks[endIndex].DerivativeInformation, singleOrder);
                        FileTracing.TraceVerbose("SquareOff attempted: OrderPlaced=" + orderPlaced + ". OrderDetails=" + singleOrder);
                    }
                }
            }


            // Internal State Check ////
            int numCurrentShortPositions = 0, numCurrentLongPositions = 0;
            for (int i = mOrders.Count - 1; i >= 0; i--)
            {
                if (mOrders[i].OrderPosition == Position.None)
                {
                    mOrders.RemoveAt(i);
                }
                else if (mOrders[i].OrderPosition == Position.Buy)
                {
                    numCurrentLongPositions++;
                }
                else if (mOrders[i].OrderPosition == Position.Sell)
                {
                    numCurrentShortPositions++;
                }
            }


            // Check 1
            // One SquareOff order already placed, not trying to place fresh order in this same tick, wait for next tick
            // return
            if (orderPlaced)
            {
                //only place one order during a tick, since the execution 
                //of the order will fulfil one buyer or one seller, and
                //we should now get the latest prices.
                FileTracing.TraceVerbose("FreshPositionChecks: One order already placed, not attempting to start new position");
                mTickLastSquareOffDone = mTotalTickCount;
                return true;
            }

            // Check 1.1
            // Wait for 10 ticks atleast from last squareoff to take an informed (not hasty) decision
            // true opportunity missed is OK rather than getting stuck in false one due to quick changes in price.
            if ((mTotalTickCount - mTickLastSquareOffDone) < 10)
            {
                FileTracing.TraceVerbose("FreshPositionChecks: Last SquareOff done recently, waiting to judge market direction to start new position");
                return false;
            }
            // Check 2
            if (mOrders.Count >= mMaxTotalPositions)
            {
                FileTracing.TraceVerbose("FreshPositionChecks: Discarding: MaxTotalPositions");
                return false;
            }

            // Check 3
            // Direction PercChange below threshold , so return 
            if (Math.Abs(percChange) < mPercChangeThresholdForMarketDirection)
            {
                //this change is not sufficient to indicate a change in market direction
                FileTracing.TraceVerbose("FreshPositionChecks: Discarding: PercChange below \"PercentageChangeForMarketDirection\" threshold, so no new position attempts");
                return false;
            }

            bool allowShortNewPos = true;
            bool allowLongNewPos = true;

            // Check 4
            // Minimize risk by allowing to balance out
            //already have a position in this leg, hence will place new order only to balance out buy/sell sides
            if (ticks[endIndex].HasFreshPositionBeenInitiatedInCurrentLeg)
            {

                // Balance out the short and long positions, so as to maintain effective stop loss
                // in case of a big "black swan" 
                int numOpenShortPositions = 0, numOpenLongPositions = 0;
                for (int i = mOrders.Count - 1; i >= 0; i--)
                {
                    if (mOrders[i].OrderPosition == Position.Buy)
                    {
                        numOpenLongPositions++;
                    }
                    else if (mOrders[i].OrderPosition == Position.Sell)
                    {
                        numOpenShortPositions++;
                    }
                }
                // if both are equal, then no need to create another positon in same leg (old behaviour)
                // only if imbalance then try to create the position
                if (numOpenLongPositions == numOpenShortPositions)
                {
                    FileTracing.TraceVerbose("FreshPositionChecks: Already Balanced out!");
                    return false;
                }
                else if (numOpenLongPositions > numOpenShortPositions)
                {
                    allowLongNewPos = false;
                }
                else
                {
                    allowShortNewPos = false;
                }
                FileTracing.TraceVerbose("FreshPositionChecks: Already have a position in this leg, still to balance out allow taking new position in same Leg");

                // TOREMOVECOMMENT
                // return false;
            }

            //market direction has changed, and percentage change is significant.

            /////////////////////////////////////////////////////////
            ///// Try taking 1 long or short position here /////////
            ////////////////////////////////////////////////////////
            // New Long position
            if (percChange > 0)
            {
                //market is going up
                if (mAllowLong)
                {
                    if (!allowLongNewPos || numCurrentLongPositions >= mMaxLongPositions)
                    {
                        FileTracing.TraceVerbose("FreshLong: Discarding: Hit MaxLongPositions!");
                    }
                    else
                    {
                        //buy a new lot
                        FileTracing.TraceVerbose("FreshLong: Attempting ...");

                        double lowPositionExistRange = 0, highPositionExistRange = 0;
                        bool orderValid = true;
                        double orderPrice = ticks[endIndex].DerivativeInformation.OfferPriceDouble;

                        // Apply LongCeiling price filter
                        if (mLongCeilingPrice > 0 && orderPrice > mLongCeilingPrice)
                        {
                            FileTracing.TraceVerbose("FreshLong: Discarding : LongCeilingPrice hit");
                            orderValid = false;
                        }

                        // Filter out the existing open position price ranges
                        for (int i = mOrders.Count - 1; i >= 0 && orderValid; i--)
                        {
                            if (mOrders[i].OrderPosition == Position.Buy)
                            {
                                // Place new leg orders 1% away from existing positions
                                // calculate the restrcited range and if the potential orderprice falls
                                // in this range then dont initiate this position as we already got a similar position
                                lowPositionExistRange = (1 - mPositionSpacingPerc / 100) * mOrders[i].OrderPrice;
                                highPositionExistRange = (1 + mPositionSpacingPerc / 100) * mOrders[i].OrderPrice;
                                if (orderPrice > lowPositionExistRange &&
                                    orderPrice < highPositionExistRange)
                                {
                                    FileTracing.TraceVerbose("FreshLong: Discarding: \"SpacingPerc\"");
                                    orderValid = false;
                                    break;
                                }
                            }
                        }
                        // Place only if order is out of exisitng position ranges
                        if (orderValid)
                        {
                            FileTracing.TraceVerbose("FreshLong: All checks passed, order is valid");
                            StockOrder newOrder = new StockOrder(Position.None, 0);
                            if (PlaceOrder(Position.Buy, newOrder, ticks[endIndex].DerivativeInformation))
                            {
                                //mTotalBuyTrades++;
                                System.Diagnostics.Debug.Assert(newOrder.OrderPosition != Position.None);
                                mOrders.Add(newOrder);
                                ticks[endIndex].HasFreshPositionBeenInitiatedInCurrentLeg = true;
                                ticks[endIndex].Order = newOrder;
                                FileTracing.TraceVerbose("FreshLong: Successful");
                                return true;
                            }
                            else
                            {
                                FileTracing.TraceVerbose("FreshLong: Failed due to IOC");
                            }
                        }
                    }
                }
            }
            // New Short position
            else if (percChange < 0)
            {
                //market is going down.
                if (mAllowShort)
                {
                    if (!allowShortNewPos || numCurrentShortPositions >= mMaxShortPositions)
                    {
                        FileTracing.TraceVerbose("FreshShort: Discarding: Hit MaxShortPositions!");
                    }
                    else
                    {
                        //sell a new lot          
                        FileTracing.TraceVerbose("FreshShort: Attempting ...");

                        double lowPositionExistRange = 0, highPositionExistRange = 0;
                        bool orderValid = true;
                        double orderPrice = ticks[endIndex].DerivativeInformation.OfferPriceDouble;

                        // Apply ShortFloor price filter
                        if (mShortFloorPrice > 0 && orderPrice < mShortFloorPrice)
                        {
                            FileTracing.TraceVerbose("FreshShort: Discarding : ShortFloorPrice has hit");
                            orderValid = false;
                        }

                        // Filter out the existing open position price ranges
                        for (int i = mOrders.Count - 1; i >= 0 && orderValid; i--)
                        {
                            if (mOrders[i].OrderPosition == Position.Sell)
                            {
                                // Place new leg orders 1% away from existing positions
                                // calculate the restrcited range and if the potential orderprice falls
                                // in this range then dont initiate this position as we already got a similar position
                                lowPositionExistRange = (1 - mPositionSpacingPerc / 100) * mOrders[i].OrderPrice;
                                highPositionExistRange = (1 + mPositionSpacingPerc / 100) * mOrders[i].OrderPrice;
                                if (orderPrice > lowPositionExistRange &&
                                    orderPrice < highPositionExistRange)
                                {
                                    FileTracing.TraceVerbose("FreshShort: Discarding : \"SpacingPerc\"");
                                    orderValid = false;
                                    break;
                                }
                            }
                        }
                        // Place only if order is out of exisitng position ranges
                        if (orderValid)
                        {
                            FileTracing.TraceVerbose("FreshShort: All checks passed, order is valid");
                            StockOrder newOrder = new StockOrder(Position.None, 0);
                            if (PlaceOrder(Position.Sell, newOrder, ticks[endIndex].DerivativeInformation))
                            {
                                //mTotalSellTrades++;
                                System.Diagnostics.Debug.Assert(newOrder.OrderPosition != Position.None);
                                mOrders.Add(newOrder);
                                ticks[endIndex].HasFreshPositionBeenInitiatedInCurrentLeg = true;
                                ticks[endIndex].Order = newOrder;
                                FileTracing.TraceVerbose("FreshShort: Successful");
                                return true;
                            }
                            else
                            {
                                FileTracing.TraceVerbose("FreshShort: Failed due to IOC ");
                            }
                        }
                    }
                }
            }

            return false;
        }

        bool PlaceOrder(Position position,
            StockOrder singleOrder,
            DerivativeQuoteInformation di)
        {

            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            double executionPrice = -1;

            string orderReference = null;
            OrderDirection orderDirection;
            double orderPrice;
            bool hasOrderExecuted;
            int tradeQuantity = mQuantity;

            if (position == Position.Buy)
            {
                orderPrice = di.OfferPriceDouble;
                orderDirection = OrderDirection.BUY;
            }
            else if (position == Position.Sell)
            {
                orderPrice = di.BidPriceDouble;
                orderDirection = OrderDirection.SELL;
            }
            else
            {
                throw new NotSupportedException("Position=" + position);
            }

            //string str = DateTime.Now.ToLongDateString() + "T " + DateTime.Now.ToLongTimeString() + ". Placing order. Position=" + position.ToString() + ". BidPrice=" + orderPrice + ". Quantity=" + tradeQuantity;
            string str;
            //str = DateTime.Now.ToLongDateString() + " T " + di.UpdateTime.ToLongTimeString() + ". Placing order. Position=" + position.ToString() + ". BidPrice=" + orderPrice + ". Quantity=" + tradeQuantity;
            str = di.UpdateTime.ToLongDateString() + " " + di.UpdateTime.ToLongTimeString() + ". Placing order. Position=" + position.ToString() + ". BidPrice=" + orderPrice + ". Quantity=" + tradeQuantity;
            //FileTracing.TraceOut(str);
            FileTracing.TraceInformation(str);
            Beep(100, 50);

            // Place order
            while (true)
            {
                if (mMock || mIsReplayMode)
                {
                    errorCode = BrokerErrorCode.Success;
                    orderReference = "Mock Order";
                }
                else
                {
                    errorCode = mBroker.PlaceDerivativeOrder(mStockCode,
                       tradeQuantity,
                       orderPrice,
                       OrderPriceType.LIMIT,
                       orderDirection,
                       mInstrumentType,
                       mExpiryDate,
                       OrderGoodNessType.IOC,
                       out orderReference);
                }

                if (errorCode == BrokerErrorCode.NotLoggedIn)
                {
                    mBroker.LogOut();
                    errorCode = mBroker.CheckAndLogInIfNeeded(true);
                    continue;
                }
                if (errorCode == BrokerErrorCode.Success)
                {
                    break;
                }
                // BUGBUGC: handle the exception, Insufficient funds etc. all
                throw new Exception("BSA:PlaceOrder:ErrorCode=" + errorCode);
            }

            // Check order status and execution price

            if (!(mMock || mIsReplayMode))
            {
                hasOrderExecuted = LoopUntilFutureOrderIsExecutedOrCancelled(orderReference, out executionPrice);
            }
            else
            {
                hasOrderExecuted = true;
            }

            if (hasOrderExecuted)
            {
                singleOrder.OrderPrice = executionPrice != -1 ? executionPrice : orderPrice;
                TotalTurnover += singleOrder.OrderPrice * mQuantity;
                if (position == Position.Buy)
                {
                    if (singleOrder.OrderPosition == Position.Sell)
                    {
                        singleOrder.OrderPosition = Position.None;
                        singleOrder.OrderPrice = 0;
                    }
                    else if (singleOrder.OrderPosition == Position.None)
                    {
                        singleOrder.OrderPosition = Position.Buy;
                    }
                    mTotalBuyTrades++;
                    FileTracing.TraceInformation("Trade Confirmed at " + singleOrder.OrderPrice + ": Order Reference Number = " + orderReference);
                }

                else if (position == Position.Sell)
                {
                    if (singleOrder.OrderPosition == Position.None)
                    {
                        singleOrder.OrderPosition = Position.Sell;
                    }
                    else if (singleOrder.OrderPosition == Position.Buy)
                    {
                        singleOrder.OrderPosition = Position.None;
                        singleOrder.OrderPrice = 0;
                    }
                    mTotalSellTrades++;
                    FileTracing.TraceInformation("Trade Confirmed at " + singleOrder.OrderPrice + ": Order Reference Number = " + orderReference);
                }

                return true;
            }
            else
            {
                mTotalFailedOrders++;
                FileTracing.TraceInformation("No Trade");
                return false;
            }
        }

        private bool LoopUntilFutureOrderIsExecutedOrCancelled(string orderReference, out double executionPrice)
        {
            executionPrice = -1;
        
            while (true)
            {
                DateTime fromDate = DateTime.Now;
                DateTime toDate = DateTime.Now;
                OrderStatus orderStatus;
                BrokerErrorCode errorCode = BrokerErrorCode.Success;

                // Incase of mock or testing replay
                if (mMock || mIsReplayMode)
                {
                    orderStatus = OrderStatus.EXECUTED;
                }
                else
                {
                    errorCode = mBroker.GetOrderStatus(orderReference,
                                            mInstrumentType, fromDate, toDate, out orderStatus);
                }

                // If fatal error then come out
                if (BrokerUtils.IsErrorFatal(errorCode))
                {
                    FileTracing.TraceOut("PlaceOrder: Fatal Error " + errorCode.ToString());
                    return false;
                }

                // EXECUTED
                if (orderStatus.Equals(OrderStatus.EXECUTED))
                {
                    int retryCount = 0;

                    if (!(mMock || mIsReplayMode))
                    {
                        // Get actual execution price
                        do
                        {
                            executionPrice = mBroker.GetTradeExecutionPrice(fromDate, toDate, mInstrumentType, orderReference);
                        } while (executionPrice == -1 && retryCount++ <= 2);
                    }
                    return true;
                }


                if (orderStatus == OrderStatus.REJECTED ||
                    orderStatus == OrderStatus.CANCELLED ||
                    orderStatus == OrderStatus.EXPIRED)
                {
                    return false;
                }
            }
        }

        /// <returns>true if a trade occurred, otherwise false</returns>
        bool PossibleSquareOff(DerivativeQuoteInformation di, StockOrder singleOrder)
        {
            System.Diagnostics.Debug.Assert(singleOrder.OrderPosition != Position.None);

            if (singleOrder.OrderPosition == Position.Buy)
            {
                double profitAmount = di.BidPriceDouble - singleOrder.OrderPrice;
                double brokerage = (1.4 * mBrokerage * di.BidPriceDouble / 100);
                if (profitAmount > 0)
                {
                    double profitPerc = 100 * (profitAmount / singleOrder.OrderPrice);
                    if (profitPerc > mMinimumProfitPercentage)
                    {
                        if (PlaceOrder(Position.Sell, singleOrder, di))
                        {
                            mTotalProfit += (profitAmount - brokerage);
                            mTotalBrokerage += brokerage;
                            //mTotalSellTrades++;
                            FileTracing.TraceInformation("SquareOff: Profit Amount (after brokerage) = " + profitAmount);
                            return true;
                        }
                    }
                    return false;
                }
                else if (profitAmount < 0)
                {
                    double lossPerc = -100 * (profitAmount / singleOrder.OrderPrice);
                    if (lossPerc > mStopLossPercentage)
                    {
                        if (PlaceOrder(Position.Sell, singleOrder, di))
                        {
                            mTotalProfit += (profitAmount - brokerage);
                            mTotalBrokerage += brokerage;
                            //mTotalSellTrades++;
                            FileTracing.TraceInformation("SquareOff: Loss Amount (after brokerage) = " + profitAmount);
                            return true;
                        }
                    }
                    return false;
                }
                else
                {
                    System.Diagnostics.Debug.Assert(profitAmount == 0);
                    return false;
                }
            }

            else if (singleOrder.OrderPosition == Position.Sell)
            {
                double profitAmount = singleOrder.OrderPrice - di.OfferPriceDouble;
                double brokerage = (1.4 * mBrokerage * di.OfferPriceDouble / 100);
                if (profitAmount > 0)
                {
                    double profitPerc = 100 * profitAmount / di.OfferPriceDouble;
                    if (profitPerc > mMinimumProfitPercentage)
                    {
                        if (PlaceOrder(Position.Buy, singleOrder, di))
                        {
                            mTotalProfit += (profitAmount - brokerage);
                            mTotalBrokerage += brokerage;
                            FileTracing.TraceInformation("SquareOff: Profit Amount (after brokerage) = " + profitAmount);
                            return true;
                        }
                    }
                    return false;
                }
                else if (profitAmount < 0)
                {
                    double lossPerc = -100 * (profitAmount / singleOrder.OrderPrice);
                    if (lossPerc > mStopLossPercentage)
                    {
                        if (PlaceOrder(Position.Buy, singleOrder, di))
                        {
                            mTotalProfit += (profitAmount - brokerage);
                            mTotalBrokerage += brokerage;
                            FileTracing.TraceInformation("SquareOff: Loss Amount (after brokerage) = " + profitAmount);
                            return true;
                        }
                    }
                    return false;
                }
                else
                {
                    System.Diagnostics.Debug.Assert(profitAmount == 0);
                    return false;
                }
            }

            else
            {
                throw new NotSupportedException();
            }
        }





        // ------- ITradingAlgo Interface methods -------- //

        public BrokerErrorCode Prolog()
        {
            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            string traceString = "----- Starting MKD_FutureTrader Thread ----- \n";

            traceString += "Algo2_BuySellAnalyzer.Prolog :: ENTER";

            FileTracing.TraceOut(traceString);

            if (!mIsReplayMode)
            {
                errorCode = mBroker.CheckAndLogInIfNeeded(false);
                if (errorCode != BrokerErrorCode.Success)
                {
                    FileTracing.TraceOut("ERROR: LogIn(). BrokerErrorCode=" + errorCode.ToString());
                }
            }
            try
            {
                if (!File.Exists(mPositionsFile))
                {
                    FileStream fs = File.Create(mPositionsFile);
                    fs.Close();
                }
                using (FileStream fs = new FileStream(mPositionsFile, FileMode.Open, FileAccess.Read))
                {
                    using (StreamReader sr = new StreamReader(fs))
                    {
                        string s = null;
                        s = sr.ReadLine();
                        string[] parts;

                        if (s != null)
                        {
                            parts = s.Split(';');

                            double.TryParse(parts[0], out mCummulativeProfitBooked);

                            do
                            {
                                s = sr.ReadLine();
                                if (s != null)
                                {
                                    parts = s.Split(';');
                                    Position position = (Position)Enum.Parse(typeof(Position), parts[0]);
                                    double price = 0;
                                    if (double.TryParse(parts[1], out price))
                                    {
                                        StockOrder order = new StockOrder(position, price);
                                        // MGOYAL: BUGBUG
                                        // This is a hack to get AvgTradePrice to be non-zero in case of off-market run
                                        // and some initial orders being present
                                        mAverageTradePrice = price;
                                        mOrders.Add(order);
                                        Console.WriteLine("InitialOrder = " + order);
                                    }
                                }
                            } while (s != null);
                        }
                    }
                }
            }
            catch(IOException e)
            {
                
            }

            traceString = "Algo2_BuySellAnalyzer.Prolog :: EXIT";
            FileTracing.TraceOut(traceString);

            return errorCode;
        }

        public BrokerErrorCode RunCoreAlgo()
        {
            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            // replay bsa text file
            if (mIsReplayMode && !bReplayDone)
            {
                #region ReplayBSATicksFile
                bReplayDone = true;

                List<DerivativeQuoteInformation> dqis = new List<DerivativeQuoteInformation>(10000);

                using (FileStream fs = new FileStream(mReplayTickFile, FileMode.Open, FileAccess.Read))
                {
                    using (StreamReader sr = new StreamReader(fs))
                    {
                        string s = null;
                        do
                        {
                            s = sr.ReadLine();
                            if (s != null)
                            {
                                string[] parts = s.Split(';');

                                IFormatProvider culture = new CultureInfo("en-US", true);
                                DateTime dt = DateTime.ParseExact(parts[0], "yyyyMMdd:HH:mm:ss", culture);
                                int volumeTraded = 0;
                                if (parts.Length == 7)
                                {
                                    volumeTraded = int.Parse(parts[6]);
                                }

                                DerivativeQuoteInformation dqi = new DerivativeQuoteInformation(
                                    dt,
                                    double.Parse(parts[1]),
                                    double.Parse(parts[2]),
                                    double.Parse(parts[3]),
                                    int.Parse(parts[4]),
                                    int.Parse(parts[5]),
                                    volumeTraded
                                    );

                                // Add to list of DQI 
                                dqis.Add(dqi);
                            }
                        } while (s != null);
                    }
                }

                // Run for each quote tick now out of all collected from the replay file
                foreach (DerivativeQuoteInformation dqi in dqis)
                {
                    mTotalTickCount++;

                    AddTick(dqi, true, false);

                    ltp = dqi.LastTradedPriceDouble;
                }


                #endregion
            }
            else if(!mIsReplayMode)
            {
                #region ActualAlgoLoop
                // run bsa analyzer in loop
                DerivativeQuoteInformation di;
                errorCode = mBroker.GetDerivativeQuote(mStockCode,
                     mInstrumentType,
                     mExpiryDate,
                     0,
                     out di);

                if (errorCode.Equals(BrokerErrorCode.Success))
                {
                    mTotalTickCount++;
                    AddTick(di, true, false);
                    ltp = di.LastTradedPriceDouble;
                }
                else
                {
                    FileTracing.TraceOut("MKD_FutureTrader: " + errorCode.ToString());
                }
                #endregion
            }
            return errorCode;
        }

        public BrokerErrorCode Epilog()
        {
            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            string traceString;
            //traceString = "Total Trades : \n" + "Buy: " + TotalBuyTrades + ", Sell: " + TotalSellTrades + "\n";
            //double tradeBrokerage = 0.7 * mBrokerage / 100 * TotalTurnover;
            //traceString += "Total brokerage : " + tradeBrokerage + "\n";
            //traceString += "Total Profit (after brokerage) : " + (TotalProfit - tradeBrokerage).ToString() + "\n";
            //traceString += "Current open positions:\n";
            //foreach (Order o in GetCurrentOpenPositions())
            //{
            //    traceString += "OrderDetails: " + o.ToString() + "\n";
            //}

            //FileTracing.TraceOut(traceString);

            // Write the open positions back into file for the next session
            List<StockOrder> openPositions = GetCurrentOpenPositions();
            AlgoRunStats stats = GetEODStats(ltp);
            ProfitLossStats plStats = stats.plStats;
            ProgramStats progStats = stats.progStats;

            mCummulativeProfitBooked += plStats.profit;
            mNettFruitIfSquaredOffAtLTP = mCummulativeProfitBooked + plStats.outstanding;

            // Write back open positions file
            using (FileStream fs = new FileStream(mPositionsFile, FileMode.Create, FileAccess.Write))
            {
                using (StreamWriter sw = new StreamWriter(fs))
                {
                    string str = mCummulativeProfitBooked + ";" + mNettFruitIfSquaredOffAtLTP;
                    sw.WriteLine(str);
                    foreach (StockOrder order in openPositions)
                    {
                        str = order.OrderPosition + ";" + order.OrderPrice;
                        sw.WriteLine(str);
                    }
                }
            }

            TraceSummary(ltp);
            FileTracing.FlushTraces();
            
            // Save a backup of the positions, trace and ticks file
            if (!mIsReplayMode)
            {
                string backupPath = SystemUtils.GetStockFilesBackupLocation();

                string dateWiseFolder = DateTime.Today.ToString("yyyyMMdd");

                string fullBackupPath = backupPath + "\\" + dateWiseFolder + "\\" + Guid.NewGuid().ToString() + "\\";


                if(!Directory.Exists(fullBackupPath))
                {
                    Directory.CreateDirectory(fullBackupPath);
                }

                

                if(File.Exists(mTickFileName)) File.Copy(mTickFileName, fullBackupPath + mStockCode + "-Ticks.txt", false);
                if (File.Exists(mTraceFileName)) File.Copy(mTraceFileName, fullBackupPath + mStockCode + "-Trace.txt", false);
                if (File.Exists(mPositionsFile)) File.Copy(mPositionsFile, fullBackupPath + mStockCode + "-Positions.txt", false);
            }


            // Program stats
            traceString = "Total failed orders : " + progStats.failedOrders + "\n";
            FileTracing.TraceOut(traceString);
            FileTracing.TraceOut("----- Exiting MKD_FutureTrader Thread ----- \n");
            return errorCode;
        }

        public int GetSleepTimeInMilliSecs()
        {
            // 2 second sleep
            return 2000;
        }

        // ------- Tracing tradeSummary  methods -------- //

        public List<StockOrder> GetCurrentOpenPositions()
        {
            List<StockOrder> list = new List<StockOrder>();
            foreach (StockOrder o in mOrders)
            {
                list.Add(new StockOrder(o));
            }
            return list;
        }

        public AlgoRunStats GetEODStats(double ltp)
        {
            AlgoRunStats stats = new AlgoRunStats();
            ProfitLossStats plStats = stats.plStats;
            ProgramStats progStats = stats.progStats;

            plStats.buyTrades = TotalBuyTrades;
            plStats.sellTrades = TotalSellTrades;
            double brokerage = TotalBrokerage * mQuantity;
            plStats.brokerage = brokerage;
            double profitAmt = TotalProfit * mQuantity;
            plStats.profit = profitAmt;

            double buyAmt = 0, sellAmt = 0;
            int buyPos = 0, sellPos = 0;

            foreach (StockOrder order in GetCurrentOpenPositions())
            {
                if (order.OrderPosition == Position.Buy)
                {
                    buyAmt += order.OrderPrice;
                    buyPos++;
                }
                else if (order.OrderPosition == Position.Sell)
                {
                    sellAmt += order.OrderPrice;
                    sellPos++;
                }
            }

            buyAmt /= (buyPos > 0) ? buyPos : 1;
            sellAmt /= (sellPos > 0) ? sellPos : 1;

            int loop = Math.Min(buyPos, sellPos);

            buyPos -= loop;
            sellPos -= loop;

            double nettOpenPosition = (sellAmt - buyAmt) * loop;
            if (buyPos > sellPos)
            {
                nettOpenPosition += (ltp - buyAmt) * buyPos;
            }
            else
            {
                nettOpenPosition += (sellAmt - ltp) * sellPos;
            }
            // 1.4 is for same day squareopff trades
            brokerage = (mBrokerage / 100 * ltp) * (1.4 * loop + Math.Abs(buyPos - sellPos));
            nettOpenPosition -= brokerage;
            nettOpenPosition *= mQuantity;
            plStats.outstanding = nettOpenPosition;
            double nettDay = profitAmt + nettOpenPosition;
            plStats.nettAfterSquareOff = nettDay;

            progStats.failedOrders = TotalFailedOrders;
            return stats;
        }

        public void TraceSummary(double ltp)
        {
            ltp = ltp != 0 ? ltp : mAverageTradePrice != 0 ? mAverageTradePrice : 1;
            FileTracing.TraceInformation(" \n\n----------------------------------------------- ");
            FileTracing.TraceInformation(string.Format("Trades: Buy = {0} Sell = {1}", TotalBuyTrades, TotalSellTrades));
            FileTracing.TraceInformation("Total Trade Diff.(after brokerage) : " + TotalProfit);
            FileTracing.TraceInformation("Total Trade Diff.(after brokerage) %: " + (TotalProfit / ltp) * 100);
            double brokerage = TotalBrokerage * mQuantity;
            FileTracing.TraceInformation("Total Brokerage : " + brokerage);
            double profitAmt = TotalProfit * mQuantity;
            FileTracing.TraceInformation("Total Profit (after brokerage) : " + profitAmt);
            FileTracing.TraceInformation("Open Positions");
            double buyAmt = 0, sellAmt = 0;
            int buyPos = 0, sellPos = 0;
            // double sellAmt = 0;
            foreach (StockOrder order in GetCurrentOpenPositions())
            {
                FileTracing.TraceInformation("OrderDetails: " + order.ToString());
                if (order.OrderPosition == Position.Buy)
                {
                    buyAmt += order.OrderPrice;
                    buyPos++;
                }
                else if (order.OrderPosition == Position.Sell)
                {
                    sellAmt += order.OrderPrice;
                    sellPos++;
                }
            }

            buyAmt /= (buyPos > 0) ? buyPos : 1;
            sellAmt /= (sellPos > 0) ? sellPos : 1;

            int loop = Math.Min(buyPos, sellPos);

            buyPos -= loop;
            sellPos -= loop;

            double nettOpenPosition = (sellAmt - buyAmt) * loop;
            if (buyPos > sellPos)
            {
                nettOpenPosition += (ltp - buyAmt) * buyPos;
            }
            else
            {
                nettOpenPosition += (sellAmt - ltp) * sellPos;
            }
            brokerage = (mBrokerage / 100 * ltp) * (1.4 * loop + Math.Abs(buyPos - sellPos));
            nettOpenPosition -= brokerage;
            FileTracing.TraceInformation("Outstanding Trade Diff. (after brokerage) : " + nettOpenPosition);
            FileTracing.TraceInformation("LTP : " + ltp);
            nettOpenPosition *= mQuantity;
            FileTracing.TraceInformation("Nett outstanding (after brokerage) : " + nettOpenPosition);
            double nettDay = profitAmt + nettOpenPosition;
            FileTracing.TraceInformation("Nett fruit if squared off at LTP's Trade Diff. : " + nettDay / mQuantity);
            FileTracing.TraceInformation("Nett fruit Amount : " + nettDay);
            int marginPositions = Math.Max(mMaxLongPositions, mMaxShortPositions);
            double moneyInvested = mQuantity * marginPositions * ltp * 0.20;
            FileTracing.TraceInformation("Money Invested : " + moneyInvested);
            double nettPerc = 100 * nettDay / moneyInvested;
            FileTracing.TraceInformation("Nett ROI percentage made : " + nettPerc);
            FileTracing.TraceInformation(" -----------------------------------------------\n\n ");
        }

        #region Windows APIs

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern Boolean Beep(UInt32 frequency, UInt32 duration);

        #endregion
    }
}
